package ac.svn.accesscontrol.controller;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;

import ac.notification.event.INotificationListener;
import ac.notification.event.NotificationEvent;
import ac.notification.manager.NotificationRegistrar;
import ac.svn.accesscontrol.manager.SVNInfoManager;
import ac.svn.accesscontrol.store.Dictionary;
import ac.svn.accesscontrol.store.IConstants;
import ac.svn.accesscontrol.store.IResources;
import ac.svn.accesscontrol.store.ISVNIdentifier;
import ac.svn.accesscontrol.store.ISVNItem;
import ac.svn.accesscontrol.store.SVNGroup;
import ac.svn.accesscontrol.store.SVNLocation;
import ac.svn.accesscontrol.store.SVNUser;
import ac.svn.accesscontrol.ui.IUIConstants;
import ac.svn.accesscontrol.ui.LocationFilterByUser;
import ac.svn.accesscontrol.ui.UIComponentLibrary;
import ac.svn.accesscontrol.ui.helper.ContentLister;
import ac.svn.accesscontrol.ui.helper.LocationFilter;
import ac.svn.accesscontrol.ui.helper.SVNItemFilter;
import ac.svn.accesscontrol.ui.helper.TreePopulator;
import ac.svn.accesscontrol.ui.window.MainWindow;
import ac.svn.accesscontrol.utils.UIUtility;
import ac.svn.accesscontrol.utils.Utility;

public class UIController implements INotificationListener,ISVNIdentifier,IUIConstants{

	private ContentLister locationLister;
	private ContentLister accessLister;
	private TreePopulator treePopulator;
	private SVNItemFilter itemFilter;
	private JTextField userSearchTxt;
	private JTextField locationSearchTxt;
	private LocationFilter locationFilter;
	private SVNInfoManager infoManager;
	private LocationFilterByUser locatoinFilter;

	private Set<String> subscriptions;
	private JMenu menu;
	private JMenuItem reloadMI;
	private JMenuItem clearDefaultMI;
	private JMenuItem openFileMI,exitMI;
	private JList locationListView;
	private JTree svnTree;
	private MainWindow mainWindow;

	public UIController()
	{
		subscriptions 		= new HashSet<String>();
		locationListView 	= (JList) UIComponentLibrary.getComponent(C_LOCATION_LIST);
		mainWindow 		= (MainWindow) UIComponentLibrary.getComponent(C_MAIN_WINDOW);

		svnTree 		= (JTree) UIComponentLibrary.getComponent(C_USERS_TREE);

		treePopulator 		= new TreePopulator(C_USERS_TREE, C_ROOT_NODE);
		treePopulator.setListClrRequired(true);
		ListingController.getListingController().registerListerForNotifications(treePopulator, ListingController.GROUP);
		//		ListingController.getListingController().registerListerForNotifications(treePopulator, ListingController.USER);

		locationLister 		= new ContentLister(C_LOCATION_LIST, C_LOCATION_MODEL);
		locationLister.setListClrRequired(true);
		ListingController.getListingController().registerListerForNotifications(locationLister, ListingController.LOCATION);

		accessLister 		= new ContentLister(C_ACCESS_LIST, C_ACCESS_MODEL);
		accessLister.setListClrRequired(true);
		ListingController.getListingController().registerListerForNotifications(accessLister, ListingController.ACCESS);

		locatoinFilter 		= new LocationFilterByUser(C_LOCATION_LIST, C_LOCATION_MODEL);

		itemFilter 		= new SVNItemFilter();
		locationFilter 		= new LocationFilter(C_LOCATION_LIST, C_LOCATION_MODEL);

		userSearchTxt		=  (JTextField) UIComponentLibrary.getComponent(C_TEXT_S_USER);
		locationSearchTxt 	=  (JTextField) UIComponentLibrary.getComponent(C_TEXT_S_LOCATION);

		menu 			= (JMenu) UIComponentLibrary.getComponent(M_ACTION_MENU);
		reloadMI 		= new JMenuItem("Reload",'R');
		reloadMI.setIcon(Utility.getImageIcon(IResources.LOC_ICN_REFRESH));
		openFileMI 		= new JMenuItem("Open..",'O');
		openFileMI.setIcon(Utility.getImageIcon(IResources.LOC_ICN_OPEN_S));

		exitMI 	= new JMenuItem("Exit",'X');
		exitMI.setIcon(Utility.getImageIcon(IResources.LOC_ICN_EXIT_S));

		menu.add(reloadMI);
		menu.add(openFileMI);
		menu.add(exitMI);

		menu 		= (JMenu) UIComponentLibrary.getComponent(M_TOOL_MENU);
		clearDefaultMI 	= new JMenuItem("Clear Deafults",'C');
		clearDefaultMI.setIcon(Utility.getImageIcon(IResources.LOC_ICN_CLEAR_DEF_S));
		menu.add(clearDefaultMI);

		infoManager 	= SVNInfoManager.getInfoManager();
		NotificationRegistrar.registerListener(this);

		registerListeners();
	}

	private void registerListeners() 
	{
		userSearchTxt.addKeyListener(new KeyAdapter() 
		{
			@Override
			public void keyPressed(KeyEvent arg0) 
			{
				SwingUtilities.invokeLater(new Runnable() 
				{
					@Override
					public void run() 
					{
						String searchString = userSearchTxt.getText();
						if(null != searchString && !searchString.isEmpty() && searchString.length() > 0)
						{
							itemFilter.findNode(searchString.toLowerCase());
						}
						else
						{
							itemFilter.clearSelection();
						}
					}
				});
			}
		});

		locationSearchTxt.addKeyListener(new KeyAdapter() 
		{
			@Override
			public void keyPressed(KeyEvent arg0) 
			{
				SwingUtilities.invokeLater(new Runnable() 
				{
					@Override
					public void run() 
					{
						locationFilter.filterList(infoManager.getAllLocations(), locationSearchTxt.getText());
					}
				});
			}
		});

		locationListView.addListSelectionListener(new ListSelectionListener() 
		{
			@Override
			public void valueChanged(ListSelectionEvent lse) 
			{
				if(!lse.getValueIsAdjusting())
				{
					SVNLocation location = (SVNLocation) locationListView.getSelectedValue();

					//Check if selection are made.
					if(null == location){	return;}

					//List access rights.
					Utility.sendNotification(N_LOCATION_SELECTION,location.getLocationPath());
				}
			}
		});

		locationListView.addMouseListener(new MouseAdapter()
		{

			@Override
			public void mouseClicked(MouseEvent arg0) {
				SVNLocation location = (SVNLocation) locationListView.getSelectedValue();

				//Check if selection are made.
				if(null == location){	return;}

				//List access rights.
				Utility.sendNotification(N_LOCATION_SELECTION,location.getLocationPath());
			}
		});

		reloadMI.addActionListener(new ActionListener() 
		{
			@Override
			public void actionPerformed(ActionEvent arg0) 
			{
				Utility.sendNotification(CMD_RELOAD_FILE);
			}
		});

		openFileMI.addActionListener(new ActionListener() 
		{
			@Override
			public void actionPerformed(ActionEvent arg0) 
			{
				Utility.sendNotification(CMD_OPEN_FILE);
			}
		});

		mainWindow.getRootPane().registerKeyboardAction(new ActionListener() 
		{
			@Override
			public void actionPerformed(ActionEvent arg0) 
			{
				userSearchTxt.requestFocus();
			}
		},
		KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0),
		JComponent.WHEN_IN_FOCUSED_WINDOW);

		mainWindow.getRootPane().registerKeyboardAction(new ActionListener() 
		{
			@Override
			public void actionPerformed(ActionEvent arg0) 
			{
				locationSearchTxt.requestFocus();
			}
		},
		KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0),
		JComponent.WHEN_IN_FOCUSED_WINDOW);

		mainWindow.addWindowListener(new WindowAdapter() 
		{
			@Override
			public void windowClosing(WindowEvent arg0) 
			{
				Utility.sendNotification(CMD_EXIT_SYSTEM);
			}			
		});

		exitMI.addActionListener(new ActionListener() 
		{
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Utility.sendNotification(CMD_EXIT_SYSTEM);				
			}
		});

		svnTree.addMouseListener(new MouseAdapter() 
		{
			@Override
			public void mouseClicked(MouseEvent arg0) 
			{
				DefaultMutableTreeNode selNode = null;
				try
				{
					selNode = (DefaultMutableTreeNode) svnTree.getSelectionPath().getLastPathComponent();
				}
				catch(Exception e)
				{
					return;
				}

				//check if selection made is of type ISVIItem, as only ISVNItem type is added on node,
				//anything other type may introduce error in handling, so filtered out.
				Object selectedItem = selNode.getUserObject();
				if(selectedItem instanceof ISVNItem)
				{
					ISVNItem svnItem = (ISVNItem) selectedItem;
					if(svnItem instanceof SVNUser)
					{
						locatoinFilter.filterListByUser(svnItem.getId());				
					}
					else if(svnItem instanceof SVNGroup)
					{
						locatoinFilter.filterListByGroup(svnItem.getId());	
					}
				}
				else
				{
					locatoinFilter.listAll();
				}
			}
		});

		clearDefaultMI.addActionListener(new ActionListener() 
		{
			@Override
			public void actionPerformed(ActionEvent ae) 
			{
				Dictionary.getDictionary().setAlwaysOpen(false);
			}
		} );

		UIUtility.addPopupListener(mainWindow.getLocationListView(),IConstants.VALUE_POPUP_TYPE_LOCATION);
		UIUtility.addPopupListener(mainWindow.getSvnTree(),IConstants.VALUE_POPUP_TYPE_GROUP_USER);
	}

	@Override
	public Set<String> declaredSubscriptionSet() 
	{
		subscriptions.add(N_OPENED_FILE);
		subscriptions.add(N_LOCATION_SELECTION);
		subscriptions.add(N_LOCATION_EDITOR_VISIBILTY_CHANGE);
		subscriptions.add(N_UPDATE_INFORMATION);
		return subscriptions;
	}

	@Override
	public void receiveEvent(NotificationEvent ne) 
	{
		if(ne.getPropertyIdentifier().contains(N_OPENED_FILE))
		{
			String file = (String) ne.getPropertyValue();
			if(null != file)
			{
				mainWindow.setTitle(String.format("Smart CM [%s]", file));
			}
		}
		else if(ne.getPropertyIdentifier().contains(N_LOCATION_SELECTION))
		{
			//Get location path and dispatch event for relisting.
			String locationPath = (String) ne.getPropertyValue();

			NotificationEvent event = new NotificationEvent(N_UPDATE_LISTINGS);
			event.setPropertyValue(ListingController.ACCESS);
			event.addParameter(P_LOCATION, locationPath);
			NotificationRegistrar.dispatchNotification(event);
		}
		else if(ne.getPropertyIdentifier().contains(N_LOCATION_EDITOR_VISIBILTY_CHANGE))
		{
			Boolean visible = (Boolean) ne.getPropertyValue();
			if(Boolean.TRUE.equals(visible))
			{
				mainWindow.setState(JFrame.ICONIFIED);
			}
			else
			{
				mainWindow.setState(JFrame.NORMAL);
				Component scrollPane = (Component) UIComponentLibrary.getComponent(IUIConstants.C_LOCATION_LIST_VIEW_HOLDER);
				mainWindow.addLocationView(scrollPane);
			}

		}
		else if(ne.getPropertyIdentifier().contains(N_UPDATE_INFORMATION))
		{
			//Update UI where users are listed.
			Utility.sendNotification(N_UPDATE_LISTINGS,C_LIST_TYPE_GROUP);
			Utility.sendNotification(N_UPDATE_LISTINGS,C_LIST_TYPE_LOCATION);
			Utility.sendNotification(N_UPDATE_LISTINGS,C_LIST_TYPE_USER);
		}
	}

}
